package Signature;

use Exporter 'import';
@EXPORT = qw(
	signature 
	stringfy 
	class_sig 
	arg_sig 
	ctor_sig 
	join_namespace 
	arg_name 
	arg_line 
	arg_declaration_line
	sigs_eq);
	
	
sub new {
	my ($class, $string, $fields) = @_;
	bless $fields, $class;
	$fields->{string} = $string;
	return $fields;
}

#
# A string representationf of signature;
# Return scalar or die.
#
sub signature {
	my ($obj) = @_;
	
	if (ref($obj)) {
		if (exists $obj->{sig}) {
			return $obj->{sig}->{string};
		}
		
		if (exists $obj->{string}) {
			return $obj->{string};
		}
		
		die 'F_NOT_A_SIGNATURE_OBJECT', $obj;
	} 
	
	return $obj;
}

sub stringfySignature {
	my ($obj) = shift;
	my $signature = signature($obj);
	$signature  =~ s/:/_/g;
	$signature  =~ s/\s//g;
	$signature  =~ s/</_lt_/g;
	$signature  =~ s/>/_gt_/g;
	return $signature; 
}

sub stringfy {
	my ($pattern, $obj) = @_;
	return stringfySignature($pattern) if (!$obj);
	
	my $signature = stringfySignature($obj);
	$pattern =~ s/{}/$signature/g;
	
	return stringfySignature($pattern); 
}

sub class_sig {
	my ($fullname, $namespace) = @_;
	
	#
	# check is namespace already in
	# class name
	#
	my @names = split_namespace($fullname);
	my $name = pop @names; 
	if (@names) {
		$namespace = \@names;		
	}
	
	my $string = join_namespace($namespace) . "$name";
	
	return new Signature($string, {
		name => $name,
		namespace => $namespace
	});
}

sub arg_sig {
	my ($fullname, $namespace, $type) = @_;
	
	#
	# check is namespace already in
	# arg name
	#
	my @names = split_namespace($fullname);
	my $name = pop @names; 
	if (@names) {
		$namespace = \@names;		
	}
	
	my $string = join_namespace($namespace) . "$name" . $type;
	
	return new Signature($string, {
		name => $name,
		namespace => $namespace,
		type => $type
	});
}

sub ctor_sig {
	my (@args) = @_;
	my @arg_sigs = map { $_->{sig}->{string} } @args;
	my $string = join(', ', @arg_sigs);
	return new Signature($string, {
		args => \@args
	});
}

sub join_namespace {
	my $namespace = shift;
	
	#obtain full class name
	if (@{ $namespace }) {
		return join("::", @ { $namespace }) . "::";
	} else {
		return "";
	}
}

sub split_namespace {
	my $fullname = shift;
	if ($fullname =~ m/^[^<]*::/) {
		my @all =  split('::', $fullname);
		return @all;
	}
	
	return ($fullname);
}

sub arg_name {
	my ($index) = @_;
	return "arg_$index";
}

sub arg_declaration_line {
	my $cctor = shift;
	
	my @decls = ();
	for (my $i=0; $i< $cctor->count(); $i++) {
		push @decls, signature($cctor->arg($i)) . " " . arg_name($i);
	}
	
	return join(',', @decls);
}

sub arg_line {
	my $cctor = shift;
	
	my @argsNames = ();
	for (my $i=0; $i< $cctor->count(); $i++) {
		push @argsNames, arg_name($i);
	}
	
	return join(',', @argsNames);
}

sub sigs_eq {
	my ($sig1, $sig2) = (signature(shift), signature(shift));
	return $sig1 eq $sig2; 	
}
1;